const objectToString = (obj) => Object.prototype.toString.call(obj);

const toStringType = (obj) => objectToString(obj).slice(8, -1);

function isObject(obj) {
  return obj !== null && typeof obj === "object";
}

const isArray = (obj) => Array.isArray(obj);

const isNaN = (obj) => Number.isNaN(obj);

const isInteger = (obj) => Number.isInteger(obj);

const isType = (obj, type) => {
  return toStringType(obj) === type;
};

const isFunction = (obj) => {
  return toStringType(obj) === "Function";
};

function isBoolean(obj) {
  return toStringType(obj) === "Boolean";
}

function isString(obj) {
  return typeof obj === "string";
}

function isNumber(obj) {
  return toStringType(obj) === "Number";
}

function isPlainObject(obj) {
  return toStringType(obj) === "Object";
}

const isMap = (obj) => {
  return toStringType(obj) === "Map";
};

const isSet = (obj) => {
  return toStringType(obj) === "Set";
};

const isNull = (obj) => {
  return toStringType(obj) === "Null";
};

const isUndefined = (obj) => {
  return toStringType(obj) === "Undefined";
};

const isPromise = (obj) => {
  return toStringType(obj) === "Promise";
};

const isSymbol = (obj) => {
  return toStringType(obj) === "Symbol";
};

const isEmpty = (obj) => {
  if (isString(obj) || isArray(obj)) return obj.length === 0;
  if (isSet(obj) || isMap(obj)) return obj.size === 0;
  if (isPlainObject(obj)) return Reflect.ownKeys(obj).length === 0;
  throw new Error("Not one of [String, Array, Set, Map, PlainObject]");
};

const isOdd = (n) => !!(n & 1);
const isEven = (n) => !(n & 1);

export { isArray, isBoolean, isEmpty, isEven, isFunction, isInteger, isMap, isNaN, isNull, isNumber, isObject, isOdd, isPlainObject, isPromise, isSet, isString, isSymbol, isType, isUndefined, objectToString, toStringType };
